package com.duolebo.uteped_sdk.msg;

import android.Manifest;

import androidx.annotation.NonNull;

import com.duolebo.uteped_sdk.UTEPedEventHandler;
import com.duolebo.uteped_sdk.utils.Const;
import com.duolebo.uteped_sdk.utils.DeviceHelper;
import com.duolebo.uteped_sdk.utils.PermissionHelper;
import com.yc.nadalsdk.bean.Alarm;
import com.yc.nadalsdk.bean.BloodOxygenRemind;
import com.yc.nadalsdk.bean.DoNotDisturbInfo;
import com.yc.nadalsdk.bean.FindWearState;
import com.yc.nadalsdk.bean.HeartRateZonConfig;
import com.yc.nadalsdk.bean.NotificationConfig;
import com.yc.nadalsdk.bean.RemindConfig;
import com.yc.nadalsdk.bean.Response;
import com.yc.nadalsdk.bean.ScreenAutoLightSwitch;
import com.yc.nadalsdk.bean.WeatherErrorConfig;
import com.yc.nadalsdk.ble.open.UteBleConnection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

/**
 * @Author: LiuYang
 * @Date: 2023/12/21 12:30
 * @Description:
 */
public class DeviceOptionMessage extends BaseMessage {

    private static final String PATH = "device_options";

    private static final String KEY_ENABLE = "enable";
    private static final String KEY_LIMIT = "limit";
    public final static String KEY_notificationEnable = "notificationEnable";
    public final static String KEY_incomingEnable = "incomingEnable";
    /**
     * BaseCallback
     *
     * @param methodChannel methodChannel
     * @param eventHandler eventHandler
     */
    public DeviceOptionMessage(MethodChannel methodChannel, UTEPedEventHandler eventHandler) {
        super(methodChannel, eventHandler);
    }

    @Override
    public String getPath() {
        return PATH;
    }

    @Override
    public boolean methodCallConsumed(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        if (!call.hasArgument(Const.KEY_METHOD))
            return false;

        if (super.methodCallConsumed(call, result))
            return true;

        UteBleConnection uteBleConnection = uteBleClient.getUteBleConnection();

        boolean consumed = true;
        String method = call.argument(Const.KEY_METHOD);
        assert method != null;

        boolean enable;
        boolean success = false;
        Response<?> rsp;

        switch (method) {
            case Const.M_setContinuousHeartRate:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setContinuousHeartRate(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                    if (success) {
                        DeviceHelper.getInstance().save(method, enable);
                    }
                }
                result.success(success);
                break;

            case Const.M_setAutoHeartRate:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setAutoHeartRate(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                if (success) {
                    DeviceHelper.getInstance().save(method, enable);
                }
                result.success(success);
                break;

            case Const.M_setLowestRemind:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setLowestRemind(getRemindConfig(call));
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                result.success(success);
                break;

            case Const.M_setHighestRemind:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setHighestRemind(getRemindConfig(call));
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }

                result.success(success);
                break;

            case Const.M_setHeartRateZone:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setHeartRateZone(getHeartRateZoneConfig(call));
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }
                result.success(success);
                break;

            case Const.M_setContinuousBloodOxygen:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setContinuousBloodOxygen(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                    if (success) {
                        DeviceHelper.getInstance().save(method, enable);
                    }
                }

                result.success(success);
                break;

            case Const.M_setSciSleep:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setSciSleep(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                    if (success) {
                        DeviceHelper.getInstance().save(Const.M_setSciSleep, enable);
                    }
                }

                result.success(success);
                break;

            case Const.M_setFutureWeatherCapability:
                //0x01：未来天气；0x02：日出日落，月相，潮汐；0x03：两者都支持
                int FUTURE_WEATHER = 1;
                int SUN_MOON_TIDE = 2;

                if (uteBleClient.isConnected()) {
                    List<Integer> list = new ArrayList<>();
                    enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                    if (enable) {
                        list.add(FUTURE_WEATHER);
                        list.add(SUN_MOON_TIDE);
                    }
                    rsp = uteBleConnection.setFutureWeatherCapability(list);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }

                result.success(success);
                break;

            case Const.M_getFutureWeatherSupport:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.getFutureWeatherSupport();
                    result.success(rsp.getData());
                }
                else {
                    List<Integer> empty = new ArrayList<>();
                    result.success(empty);
                }

                break;

            case Const.M_setWeatherErrorInfo:
                if (call.hasArgument(Const.KEY_VALUE) && uteBleClient.isConnected()) {
                    // 0：网络错误；1：定位失败；2：关闭天气推送
                    int value = call.argument(Const.KEY_VALUE);
                    WeatherErrorConfig weatherErrorConfig = new WeatherErrorConfig();
                    weatherErrorConfig.setErrorInfoType(value);
                    rsp = uteBleConnection.setWeatherErrorInfo(weatherErrorConfig);
                    result.success(rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                else {
                    result.success(false);
                }
                break;

            case Const.M_setBloodOxygenRemind:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setBloodOxygenRemind(getBloodOxygenRemind(call));
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }

                result.success(success);
                break;

            case Const.M_setTimeSyncEnable:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                DeviceHelper.getInstance().save(Const.M_setTimeSyncEnable, enable);
                result.success(true);
                break;

            case Const.M_setWeightSyncEnable:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                DeviceHelper.getInstance().save(Const.M_setWeightSyncEnable, enable);
                result.success(true);
                break;

            case Const.M_setScreenAutoLight:
                if (uteBleClient.isConnected()) {
                    enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                    rsp = uteBleConnection.setScreenAutoLight(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }

                result.success(success);
                break;

            case Const.M_getScreenAutoLightState:
                Map<String, Object> sasRspMap = new HashMap<>();
                if (uteBleClient.isConnected()) {
                    Response<ScreenAutoLightSwitch> sasRsp = uteBleConnection.getScreenAutoLightState();
                    sasRspMap = objectToMap(sasRsp.getData(), true, false);
                }

                d("getScreenAutoLightState:" + sasRspMap);
                result.success(sasRspMap);
                break;

            case Const.M_setScreenOnDuration:
                if (uteBleClient.isConnected()) {
                    int duration = 5;
                    if (call.hasArgument(Const.KEY_VALUE)) {
                        duration = call.argument(Const.KEY_VALUE);
                    }
                    rsp = uteBleConnection.setScreenOnDuration(duration);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }

                result.success(success);
                break;

            case Const.M_setFindWearCmd:
                if (call.hasArgument(Const.KEY_VALUE) && uteBleClient.isConnected()) {
                    // 0:关闭(off) 1:开启(on)
                    int value = call.argument(Const.KEY_VALUE);
                    rsp = uteBleConnection.setFindWearCmd(value);
                    result.success(rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                else
                    result.success(false);
                break;

            case Const.M_getFindWearState:
                if (uteBleClient.isConnected()) {
                    Response<FindWearState> wearStateResponse = uteBleConnection.getFindWearState();
                    result.success(wearStateResponse.getData().getFindWearState());
                }
                else {
                    result.success(-1);
                }

                break;

            case Const.M_setDoNotDisturb:
                if (uteBleClient.isConnected()) {
                    Response<DoNotDisturbInfo> dndRsp = uteBleConnection.queryDeviceDoNotDisturb();
                    if (dndRsp.getErrorCode() == Const.CODE_SUCCESS) {
                        rsp = uteBleConnection.setDoNotDisturb(getDoNotDisturbInfo(call, dndRsp.getData()));
                        success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                    }
                }

                result.success(success);
                break;

            case Const.M_queryDeviceDoNotDisturb:
                Map<String, Object> map = new HashMap<>();
                if (uteBleClient.isConnected()) {
                    Response<DoNotDisturbInfo> queryDndRsp = uteBleConnection.queryDeviceDoNotDisturb();
                    map.put(Const.KEY_SUCCESS, queryDndRsp.isSuccess());
                    if (queryDndRsp.isSuccess()) {
                        map.putAll(objectToMap(queryDndRsp.getData(), true, false));
                    }
                }

                result.success(map);
                break;

            case Const.M_setAlarmList:
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setAlarmList(getAlamList(call));
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }
                result.success(success);
                break;

            case Const.M_getAlarmList:
                List<Map<String, Object>> alarmListMap = new ArrayList<>();
                if (uteBleClient.isConnected()) {
                    Response<List<? extends Alarm>> alarmRsp = uteBleConnection.getAlarmList();
                    if (alarmRsp.getErrorCode() == Const.CODE_SUCCESS) {
                        for (Alarm alarm:alarmRsp.getData()) {
                            Map<String, Object> alarmMap = objectToMap(alarm, true, false);
                            alarmListMap.add(alarmMap);
                        }
                    }
                }

                result.success(alarmListMap);
                break;

            case Const.M_setNotificationConfig:
                if (uteBleClient.isConnected()) {
                    NotificationConfig notificationConfig = new NotificationConfig();
                    if (call.hasArgument(KEY_notificationEnable)) {
                        boolean notificationEnable = Boolean.TRUE.equals(call.argument(KEY_notificationEnable));
                        notificationConfig.setNotificationEnable(notificationEnable);
                    }
                    else if (call.hasArgument(KEY_incomingEnable)) {
                        boolean incomingEnable = Boolean.TRUE.equals(call.argument(KEY_incomingEnable));
                        notificationConfig.setIncomingEnable(incomingEnable);
                    }
                    rsp = uteBleConnection.setNotificationConfig(notificationConfig);
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }

                result.success(success);
                break;

            case Const.M_setFindMyPhone:
                if (call.hasArgument(Const.KEY_VALUE) && uteBleClient.isConnected()) {
                    // 1:要求服务端报警 2:要求服务端停止报警
                    int value = call.argument(Const.KEY_VALUE);
                    rsp = uteBleConnection.setFindMyPhone(value);
                    result.success(rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                else
                    result.success(false);
                break;

            case Const.M_sendFindPhoneSwitchStatus:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.sendFindPhoneSwitchStatus(enable);
                    success = rsp.getErrorCode() == Const.CODE_SUCCESS;
                }
                result.success(success);
                break;

            case Const.M_setAutoStress:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (uteBleClient.isConnected()) {
                    rsp = uteBleConnection.setAutoStress(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }
                result.success(success);
                break;

            case Const.M_sendCameraPermission:
                enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
                if (enable && !PermissionHelper.hasPermission(Manifest.permission.CAMERA)) {
                    onCheckPermission(Manifest.permission.CAMERA);
                }
                else if(uteBleClient.isConnected()) {
                    rsp = uteBleConnection.sendCameraPermission(enable);
                    success = (rsp.getErrorCode() == Const.CODE_SUCCESS);
                }

                result.success(success);
                break;

            default:
                consumed = false;
        }

        return consumed;
    }

    private RemindConfig getRemindConfig(MethodCall call) {
        boolean enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));

        RemindConfig config = new RemindConfig();
        config.setEnable(enable);
        if (call.hasArgument(KEY_LIMIT)) {
            int limit = call.argument(KEY_LIMIT);
            config.setWarningLimit(limit);
        }

        return config;
    }

    private HeartRateZonConfig getHeartRateZoneConfig(MethodCall call) {
        HeartRateZonConfig config = new HeartRateZonConfig();
        if (call.hasArgument("warmUpRate")) {
            config.setWarmUpRate(call.argument("warmUpRate"));
        }
        if (call.hasArgument("fatBurnRate")) {
            config.setFatBurnRate(call.argument("fatBurnRate"));
        }
        if (call.hasArgument("aerobicRate")) {
            config.setAerobicRate(call.argument("aerobicRate"));
        }
        if (call.hasArgument("anaerobicRate")) {
            config.setAnaerobicRate(call.argument("anaerobicRate"));
        }
        if (call.hasArgument("lowerLimitRate")) {
            config.setLowerLimitRate(call.argument("lowerLimitRate"));
        }
        if (call.hasArgument("upperLimitRate")) {
            config.setUpperLimitRate(call.argument("upperLimitRate"));
        }
        if (call.hasArgument("rateWarnSwitch")) {
            config.setRateWarnSwitch(call.argument("rateWarnSwitch"));
        }
        if (call.hasArgument("rateWarnMaxRate")) {
            config.setRateWarnMaxRate(call.argument("rateWarnMaxRate"));
        }
        if (call.hasArgument("heartRateType")) {
            config.setHeartRateType(call.argument("heartRateType"));// HeartRateZonConfig.TYPE_RESERVE or HeartRateZonConfig.TYPE_MAX
        }
        if (call.hasArgument("maxHeartRate")) {
            config.setMaxHeartRate(call.argument("maxHeartRate"));
        }
        if (call.hasArgument("restHeartRate")) {
            config.setRestHeartRate(call.argument("restHeartRate"));
        }
        if (call.hasArgument("aerobicBase")) {
            config.setAerobicBase(call.argument("aerobicBase"));
        }
        if (call.hasArgument("aerobicAdvance")) {
            config.setAerobicAdvance(call.argument("aerobicAdvance"));
        }
        if (call.hasArgument("lacticAcid")) {
            config.setLacticAcid(call.argument("lacticAcid"));
        }
        if (call.hasArgument("anaerobicBase")) {
            config.setAnaerobicBase(call.argument("anaerobicBase"));
        }
        if (call.hasArgument("anaerobicAdvance")) {
            config.setAnaerobicAdvance(call.argument("anaerobicAdvance"));
        }

        return config;
    }

    private BloodOxygenRemind getBloodOxygenRemind(MethodCall call) {
        boolean enable = Boolean.TRUE.equals(call.argument(KEY_ENABLE));
        BloodOxygenRemind bloodOxygenRemind = new BloodOxygenRemind();
        bloodOxygenRemind.setEnable(enable);
        if (call.hasArgument(KEY_LIMIT)) {
            int limit = call.argument(KEY_LIMIT);
            bloodOxygenRemind.setLimit(limit);
        }

        return bloodOxygenRemind;
    }

    private final static String KEY_closeVibration = "closeVibration";
    private final static String KEY_closeMessageRemind = "closeMessageRemind";
    private DoNotDisturbInfo getDoNotDisturbInfo(MethodCall call, DoNotDisturbInfo dndInfo) {
        if (call.hasArgument(Const.KEY_allDayEnable)) {
            boolean allDayEnable = Boolean.TRUE.equals(call.argument(Const.KEY_allDayEnable));
            dndInfo.setAllDayEnable(allDayEnable);
        }

        if (call.hasArgument(Const.KEY_timingEnable)) {
            boolean timingEnable = Boolean.TRUE.equals(call.argument(Const.KEY_timingEnable));
            dndInfo.setTimingEnable(timingEnable);
        }

        if (call.hasArgument(Const.KEY_fromTimeHour)) {
            int fromTimeHour = call.argument(Const.KEY_fromTimeHour);
            dndInfo.setFromTimeHour(fromTimeHour);
        }

        if (call.hasArgument(Const.KEY_fromTimeMinute)) {
            int fromTimeMinute = call.argument(Const.KEY_fromTimeMinute);
            dndInfo.setFromTimeMinute(fromTimeMinute);
        }

        if (call.hasArgument(Const.KEY_toTimeHour)) {
            int toTimeHour = call.argument(Const.KEY_toTimeHour);
            dndInfo.setToTimeHour(toTimeHour);
        }

        if (call.hasArgument(Const.KEY_toTimeMinute)) {
            int toTimeMinute = call.argument(Const.KEY_toTimeMinute);
            dndInfo.setToTimeMinute(toTimeMinute);
        }

        if (call.hasArgument(KEY_closeVibration)) {
            boolean closeVibration = Boolean.TRUE.equals(call.argument(KEY_closeVibration));
            dndInfo.setCloseVibration(closeVibration);
        }

        if (call.hasArgument(KEY_closeMessageRemind)) {
            boolean closeMessageRemind = Boolean.TRUE.equals(call.argument(KEY_closeMessageRemind));
            dndInfo.setCloseMessageRemind(closeMessageRemind);
        }

        return dndInfo;
    }

    private final static String KEY_index = "index";
    private final static String KEY_enable = "enable";
    private final static String KEY_hour = "hour";
    private final static String KEY_minute = "minute";
    private final static String KEY_cycleList = "cycleList";
    private final static String KEY_name = "name";
    private final static String KEY_alarmList = "list";

    private List<Alarm> getAlamList(MethodCall call) {
        List<Alarm> alarmList = new ArrayList<>();
        if (call.hasArgument(KEY_alarmList)) {
            List<Map<String, Object>> mapList = call.argument(KEY_alarmList);
            for (Map<String, Object> mapItem:mapList) {
                Alarm alarm = new Alarm();
                if (mapItem.containsKey(KEY_index)) {
                    alarm.setIndex((Integer) mapItem.get(KEY_index));
                }
                if (mapItem.containsKey(KEY_hour)) {
                    alarm.setHour((Integer) mapItem.get(KEY_hour));
                }
                if (mapItem.containsKey(KEY_minute)) {
                    alarm.setMinute((Integer) mapItem.get(KEY_minute));
                }
                if (mapItem.containsKey(KEY_cycleList)) {
                    alarm.setCycleList((List<Integer>) mapItem.get(KEY_cycleList));
                }
                if (mapItem.containsKey(KEY_enable)) {
                    alarm.setEnable((Boolean) mapItem.get(KEY_enable));
                }
                if (mapItem.containsKey(KEY_name)) {
                    alarm.setName((String) mapItem.get(KEY_name));
                }

                alarmList.add(alarm);
            }
        }

        return alarmList;
    }
}
